/*******************************************************************************
filename      CString.cpp
author        Craig Williams

Brief Description:
  Portable version of the std::string class. This was written to get rid of
    of the different versions of std::string, that made them unsafe to use
    across .dll boundries. Namely, a debug and release mode version of
    std::string cannot be used together (the memory layout is different).

  For all intensive purposes, this is the same as std::string with a few
    modifications:
      No iterator support. I don't use them, so I left it out.

      Additional Checking:
        This class handles NULL, which std::string does not.
        A null terminator is append to the end, and it is accessable via
          the index operator and similar.
        No exceptions.

      Added Functions:
        sprintf   - Wrapper around sprintf
        writef    - Wrapper around sprintf
        ToLower   - Converts the string to lower case
        GetLower  - Returns a copy of this string as lower case
        ToUpper   - Converts the string to upper case
        GetUpper  - Returns a copy of this string as upper case
        Hash      - Generates a hash from the string
        GetAsLong - Reads sizeof(long) bytes from the string into a long. Great
                      for sorting.
*******************************************************************************/
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif

#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include "CString.h"

CString::CString(void)
{
  mStr.push_back(0);
}

CString::CString(const CString &r) : mStr(r.mStr)
{
}

CString::CString(const CString &str, unsigned int pos, unsigned int n)
{
  mStr.push_back(0);
  assign(str, pos, n);
}

CString::CString(const char *s, unsigned int n)
{
  mStr.push_back(0);
  assign(s, n);
}

CString::CString(const char *s)
{
  mStr.push_back(0);
  assign(s);
}

CString::CString(unsigned int n, char c)
{
  mStr.push_back(0);
  assign(n, c);
}

CString &CString::operator=(const CString &str)
{
  return assign(str);
}

CString &CString::operator=(const char *s)
{
  return assign(s);
}

CString &CString::operator=(char c)
{
  mStr.clear();
  mStr.push_back(c);
  mStr.push_back(0);
  return *this;
}

unsigned int CString::size(void) const
{
  return mStr.size() - 1;
}

unsigned int CString::length(void) const
{
  return size();
}

unsigned int CString::max_size(void) const
{
  return (unsigned int)~0;
}

void CString::resize(unsigned int n)
{
  mStr.pop_back();
  mStr.resize(n, 0);
  mStr.push_back(0);
}

void CString::resize(unsigned int n, char c)
{
  mStr.pop_back();
  mStr.resize(n, c);
  mStr.push_back(0);
}

unsigned int CString::capacity(void) const
{
  return mStr.capacity();
}

void CString::reserve(unsigned int res_arg)
{
  mStr.reserve(res_arg + 1); // +1 for NULL teriminator
}

void CString::clear(void)
{
  mStr.clear();
  mStr.push_back(0);
}

bool CString::empty(void) const
{
  return mStr.size() == 1;
}

const char &CString::operator[](unsigned int pos) const
{
  return at(pos);
}

char &CString::operator[](unsigned int pos)
{
  return at(pos);
}

const char &CString::at(unsigned int pos) const
{
  if(pos > mStr.size())
  {
    mGarbage = -127;
    return mGarbage;
  }
  return mStr[pos];
}

char &CString::at(unsigned int pos)
{
  if(pos > mStr.size())
  {
    mGarbage = -127;
    return mGarbage;
  }
  return mStr[pos];
}

CString &CString::operator+=(const CString &str)
{
  return append(str);
}

CString &CString::operator+=(const char *s)
{
  return append(s);
}

CString &CString::operator+=(char c)
{
  mStr.back() = c;
  mStr.push_back(0);
  return *this;
}

CString &CString::append(const CString &str)
{
  unsigned int i;
  unsigned int n;

    // Note: This must be here. If &str == this, then we will
    //         be directly modifying str as well. As such, we must
    //         get the length of the string before we modify it.
  n = str.mStr.size() - 1;

  mStr.reserve(mStr.size() + n);
  mStr.pop_back();
  for(i = 0; i < n; ++i)
    mStr.push_back(str.mStr[i]);
  mStr.push_back(0);

  return *this;
}

CString &CString::append(const CString &str, unsigned int pos, unsigned int n)
{
  unsigned int i;
  unsigned int len = str.mStr.size() - 1;

  if(pos > len)
    return *this;

  if(pos + n > len)
    n = len - pos;

  mStr.reserve(mStr.size() + n);
  mStr.pop_back();
  for(i = 0; i < n; ++i)
    mStr.push_back(str.mStr[pos + i]);
  mStr.push_back(0);

  return *this;
}

CString &CString::append(const char *s, unsigned int n)
{
  unsigned int len;
  unsigned int i;

  if(!s)
    len = 0;
  else
    len = strlen(s);

  if(n > len)
    n = len;

    // Potential crash. If s came from mStr, then if mStr grows, s can become
    //   invalid. As such, explicilty check for self assignment, and handle
    //   accordingly.
  if(SelfModification(s))
  {
    unsigned int delta = (unsigned int)(s - mStr.mData);
    mStr.reserve(mStr.size() + n);
    s = mStr.mData + delta;
  }
  else
    mStr.reserve(mStr.size() + n);

  mStr.pop_back();
  for(i = 0; i < n ; ++i)
    mStr.push_back(s[i]);
  mStr.push_back(0);

  return *this;
}

CString &CString::append(const char *s)
{
  unsigned int i;
  unsigned int n;

  if(!s)
    n = 0;
  else
    n = strlen(s);

    // Potential crash. If s came from mStr, then if mStr grows, s can become
    //   invalid. As such, explicilty check for self assignment, and handle
    //   accordingly.
  if(SelfModification(s))
  {
    unsigned int delta = (unsigned int)(s - mStr.mData);
    mStr.reserve(mStr.size() + n);
    s = mStr.mData + delta;
  }
  else
    mStr.reserve(mStr.size() + n);

  mStr.pop_back();
  for(i = 0; i < n; ++i)
    mStr.push_back(s[i]);
  mStr.push_back(0);

  return *this;
}

CString &CString::append(unsigned int n, char c)
{
  unsigned int i;

  mStr.reserve(mStr.size() + n);
  mStr.pop_back();
  for(i = 0; i < n; ++i)
    mStr.push_back(c);
  mStr.push_back(0);
  return *this;
}

void CString::push_back(char c)
{
  mStr.back() = c;
  mStr.push_back(0);
}

CString &CString::assign(const CString &str)
{
  unsigned int i;
  unsigned int n;

  n = str.mStr.size();
  mStr.reserve(n);
  mStr.RawSetCur(n);
  for(i = 0; i < n; ++i)
    mStr[i] = str.mStr[i];

  return *this;
}

CString &CString::assign(const CString &str, unsigned int pos, unsigned int n)
{
  unsigned int i;
  unsigned int len = str.mStr.size() - 1;

  if(pos >= len)
  {
    mStr.clear();
    mStr.push_back(0);
    return *this;
  }

  if(n > len - pos)
    n = len - pos;

  mStr.reserve(n + 1);
  mStr.RawSetCur(n + 1);
  for(i = 0; i < n; ++i)
    mStr[i] = str.mStr.mData[pos + i];
  mStr[i] = 0;

  return *this;
}

CString &CString::assign(const char *s, unsigned int n)
{
  unsigned int i;
  unsigned int len;

  if(!s)
  {
    mStr.clear();
    mStr.push_back(0);
    return *this;
  }

  len = strlen(s);
  if(n > len)
    n = len;

    // Note: If self assignement occurs, mStr will not be resized. This is a
    //         defined behavior of the CVector. As such, s will not be
    //         invalidated after mStr.reserve();
  mStr.reserve(n + 1);
  mStr.RawSetCur(n + 1);
  for(i = 0; i < n; ++i)
    mStr[i] = s[i];
  mStr[i] = 0;

  return *this;
}

CString &CString::assign(const char *s)
{
  unsigned int i;
  unsigned int n;

  if(!s)
  {
    mStr.clear();
    mStr.push_back(0);
    return *this;
  }

  n = strlen(s);

    // Note: If self assignement occurs, mStr will not be resized. This is a
    //         defined behavior of the CVector. As such, s will not be
    //         invalidated after mStr.reserve();
  mStr.reserve(n + 1);
  mStr.RawSetCur(n + 1);
  for(i = 0; i < n; ++i)
    mStr[i] = s[i];
  mStr[i] = 0;

  return *this;
}

CString &CString::assign(unsigned int n, char c)
{
  mStr.clear();
  mStr.resize(n, c);
  mStr.push_back(0);
  return *this;
}

CString &CString::insert(unsigned int pos1, const CString &str)
{
  return insert(pos1, str, 0, str.mStr.size() - 1);
}

CString &CString::insert(unsigned int pos1, const CString &str, unsigned int pos2, unsigned int n)
{
  unsigned int len;
  unsigned int read;
  unsigned int write;

  if(this == &str)
    return insert(pos1, CString(*this), pos2, n);

  if(pos2 > str.mStr.size())
    return *this;

  if(pos1 >= mStr.size())
    pos1 = mStr.size() - 1;

  if(pos2 + n > str.mStr.size() - 1)
    len = str.mStr.size() - 1 - pos2;
  else
    len = n;

  ShiftRight(pos1, len);

    // Copy str into mStr
  for(write = pos1, read = 0; read < len; ++write, ++read)
    mStr[write] = str.mStr[pos2 + read];

  return *this;
}

CString &CString::insert(unsigned int pos1, const char *s, unsigned int n)
{
  unsigned int read;
  unsigned int write;
  unsigned int len;

  if(!s)
    return *this;

  if(SelfModification(s))
    return insert(pos1, CString(s), 0, n);

  if(pos1 >= mStr.size())
    pos1 = mStr.size() - 1;

  len = strlen(s);
  if(n > len)
    n = len;

  ShiftRight(pos1, len);

  for(write = pos1, read = 0; read < n; ++read, ++write)
    mStr[write] = s[read];

  return *this;
}

CString &CString::insert(unsigned int pos1, const char *s)
{
  if(!s)
    return *this;
  return insert(pos1, s, strlen(s));
}

CString &CString::insert(unsigned int pos1, unsigned int n, char c)
{
  if(pos1 >= mStr.size())
    pos1 = mStr.size() - 1;

  ShiftRight(pos1, n);

  n += pos1;
  for(; pos1 < n; ++pos1)
    mStr[pos1] = c;

  return *this;
}

CString &CString::erase(unsigned int pos, unsigned int n)
{
  unsigned int read;
  unsigned int write;
  unsigned int len;

  if(pos >= mStr.size())
    return *this;

  len = mStr.size();

  if(n >= len || pos + n >= len)
    n = len - pos - 1;

  for(write = pos, read = pos + n; read < len; ++read, ++write)
    mStr[write] = mStr[read];
  mStr.RawSetCur(write);

  return *this;
}

CString &CString::replace(unsigned int pos1, unsigned int n1, const CString &str)
{
  return replace(pos1, n1, str, 0, str.mStr.size() - 1);
}

CString &CString::replace(unsigned int pos1, unsigned int n1, const CString &str, unsigned int pos2, unsigned int n2)
{
  unsigned int i;
  unsigned int len1 = mStr.size() - 1;
  unsigned int len2 = str.mStr.size() - 1;

  if(pos1 >= len1)
    return *this;

  if(this == &str)
    return replace(pos1, n1, CString(*this), pos2, n2);

  if(n1 > len1)
    n1 = len1;

  if(pos1 + n1 > len1)
    n1 = len1 - pos1;

  if(n2 > len2)
    n2 = len2;

  if(pos2 >= len2)
    pos2 = len2 - 1;

  if(pos2 + n2 > len2)
    n2 = len2 - pos2;

  if(n2 > n1)
    ShiftRight(pos1 + n1, n2 - n1);
  else
    erase(pos1 + n2, n1 - n2);

  for(i = 0; i < n2; ++i)
    mStr[pos1 + i] = str.mStr[pos2 + i];

  return *this;
}

CString &CString::replace(unsigned int pos1, unsigned int n1, const char *s, unsigned int n2)
{
  unsigned int i;
  unsigned int len1 = mStr.size() - 1;
  unsigned int len2;

  if(!s)
    len2 = 0;
  else
    len2 = strlen(s);

  if(pos1 >= len1)
    return *this;

  if(SelfModification(s))
    return replace(pos1, n1, CString(s), 0, n2);

  if(n1 > len1)
    n1 = len1;

  if(pos1 + n1 > len1)
    n1 = len1 - pos1;

  if(n2 > len2)
    n2 = len2;

  if(n2 > n1)
    ShiftRight(pos1 + n1, n2 - n1);
  else
    erase(pos1 + n2, n1 - n2);

  for(i = 0; i < n2; ++i)
    mStr[pos1 + i] = s[i];

  return *this;
}

CString &CString::replace(unsigned int pos1, unsigned int n1, const char *s)
{
  return replace(pos1, n1, s, (unsigned int)~0);
}

CString &CString::replace(unsigned int pos1, unsigned int n1, unsigned int n2, char c)
{
  unsigned int i;
  unsigned int len1 = mStr.size() - 1;

  if(pos1 >= len1)
    return *this;

  if(n1 > len1)
    n1 = len1;

  if(pos1 + n1 > len1)
    n1 = len1 - pos1;

  if(n2 > n1)
    ShiftRight(pos1 + n1, n2 - n1);
  else
    erase(pos1 + n2, n1 - n2);

  for(i = 0; i < n2; ++i)
    mStr[pos1 + i] = c;

  return *this;
}

unsigned int CString::copy(char *s, unsigned int n, unsigned int pos) const
{
  unsigned int write;
  unsigned int len1 = mStr.size();

  if(!s || pos >= len1)
    return 0;

  if(pos + n >= len1)
    n = len1 - pos - 1;

  for(write = 0; write < n; ++write, ++pos)
    s[write] = mStr[pos];

  return n;
}

void CString::swap(CString &str)
{
  CVector<char> temp = mStr;
  mStr = str.mStr;
  str.mStr = temp;
}

const char *CString::c_str(void) const
{
  return mStr.mData;
}

const char *CString::data(void) const
{
  return mStr.mData;
}

unsigned int CString::find(const CString &str, unsigned int pos) const
{
  char *loc;

  if(pos >= mStr.size() - 1)
    return (unsigned int)~0;

  loc = strstr(mStr.mData + pos, str.mStr.mData);

  if(!loc)
    return (unsigned int)~0;

  return (unsigned int)(loc - mStr.mData);
}

unsigned int CString::find(const char *s, unsigned int pos, unsigned int n) const
{
  unsigned int len1;
  unsigned int len2;
  unsigned int i;

  if(!s)
    return (unsigned int)~0;

  len1 = mStr.size() - 1;

  if(pos >= len1 - 1)
    return (unsigned int)~0;

  len2 = strlen(s);
  if(n > len2)
    n = len2;

  len1 -= n - 1;
  for(; pos < len1; ++pos)
  {
    for(i = 0; i < n && mStr[i]; ++i)
      if(mStr[pos + i] != s[i])
        break;
    if(i >= n)
      return pos;
  }

  return (unsigned int)~0;
}

unsigned int CString::find(const char *s, unsigned int pos) const
{
  return find(s, pos, (unsigned int)~0);
}

unsigned int CString::find(char c, unsigned int pos) const
{
  unsigned int len1 = mStr.size() - 1;

  if(pos >= len1)
    return (unsigned int)~0;

  for(; pos < len1; ++pos)
    if(mStr[pos] == c)
      return pos;

  return (unsigned int)~0;
}

unsigned int CString::rfind(const CString &str, unsigned int pos) const
{
  unsigned int i;
  unsigned int len1 = mStr.size() - 1;
  unsigned int len2 = str.mStr.size() - 1;

  if(pos >= len1)
    pos = len1 - 1;

  for(++pos; pos--;)
  {
    for(i = 0; i < len2; ++i)
      if(mStr[pos + i] != str.mStr[i])
        break;
    if(i >= len2)
      return pos;
  }

  return (unsigned int)~0;
}

unsigned int CString::rfind(const char *s, unsigned int pos, unsigned int n) const
{
  unsigned int i;
  unsigned int len1;
  unsigned int len2;

  if(!s)
    return (unsigned int)~0;

  len1 = mStr.size() - 1;

  if(pos >= len1)
    pos = len1 - 1;

  len2 = strlen(s);
  if(n >= len2)
    n = len2 - 1;

  for(++pos; pos--;)
  {
    for(i = 0; i < len2; ++i)
      if(mStr[pos + i] != s[i])
        break;
    if(i >= len2)
      return pos;
  }

  return (unsigned int)~0;
}

unsigned int CString::rfind(const char *s, unsigned int pos) const
{
  return rfind(s, pos, (unsigned int)~0);
}

unsigned int CString::rfind(char c, unsigned int pos) const
{
  unsigned int len1 = mStr.size() - 1;

  if(pos >= len1)
    pos = len1 - 1;

  for(++pos; pos--;)
    if(mStr[pos] == c)
      return pos;

  return (unsigned int)~0;
}

unsigned int CString::find_first_of(const CString &str, unsigned int pos) const
{
  unsigned int i;
  char c;

  if(pos >= mStr.size() - 1)
    return (unsigned int)~0;

  c = mStr[pos];
  for(; c; c = mStr[++pos])
    for(i = 0; str.mStr[i]; ++i)
      if(c == str.mStr[i])
        return pos;

  return (unsigned int)~0;
}

unsigned int CString::find_first_of(const char *s, unsigned int pos, unsigned int n) const
{
  unsigned int i;
  unsigned int len2;
  char c;

  if(!s || pos >= mStr.size() - 1)
    return (unsigned int)~0;

  len2 = strlen(s);

  if(n >= len2)
    n = len2;

  c = mStr[pos];
  for(; c; c = mStr[++pos])
    for(i = 0; i < n; ++i)
      if(c == s[i])
        return pos;

  return (unsigned int)~0;
}

unsigned int CString::find_first_of(const char *s, unsigned int pos) const
{
  return find_first_of(s, pos, (unsigned int)~0);
}

unsigned int CString::find_first_of(char c, unsigned int pos) const
{
  if(pos >= mStr.size() - 1)
    return (unsigned int)~0;

  for(; mStr[pos]; ++pos)
    if(mStr[pos] == c)
      return pos;

  return (unsigned int)~0;
}

unsigned int CString::find_last_of(const CString &str, unsigned int pos) const
{
  unsigned int i;
  unsigned int len2;
  char c;

  if(pos >= mStr.size() - 1)
    pos = mStr.size() - 2;

  len2 = str.mStr.size() - 1;

  for(++pos; pos--;)
  {
    c = mStr[pos];
    for(i = 0; i < len2; ++i)
      if(c == str.mStr[i])
        return pos;
  }

  return (unsigned int)~0;
}

unsigned int CString::find_last_of(const char *s, unsigned int pos, unsigned int n) const
{
  unsigned int i;
  unsigned int len1;
  unsigned int len2;
  char c;

  if(!s)
    return (unsigned int)~0;

  len1 = mStr.size() - 1;
  len2 = strlen(s);

  if(pos >= len1)
    pos = len1 - 1;

  if(n > len2)
    n = len2;

  for(++pos; pos--;)
  {
    c = mStr[pos];
    for(i = 0; i < n; ++i)
      if(c == s[i])
        return pos;
  }

  return (unsigned int)~0;
}

unsigned int CString::find_last_of(const char *s, unsigned int pos) const
{
  return find_last_of(s, pos, (unsigned int)~0);
}

unsigned int CString::find_last_of(char c, unsigned int pos) const
{
  unsigned int len1 = mStr.size() - 1;

  if(pos >= len1)
    pos = len1 - 1;

  for(++pos; pos--;)
    if(mStr[pos] == c)
      return pos;

  return (unsigned int)~0;
}

unsigned int CString::find_first_not_of(const CString &str, unsigned int pos) const
{
  unsigned int i;
  char c;

  if(pos >= mStr.size() - 1)
    return (unsigned int)~0;

  c = mStr[pos];
  for(; c; c = mStr[++pos])
  {
    for(i = 0; str.mStr[i]; ++i)
      if(c == str.mStr[i])
        break;
    if(!str.mStr[i])
      return pos;
  }

  return (unsigned int)~0;
}

unsigned int CString::find_first_not_of(const char *s, unsigned int pos, unsigned int n) const
{
  unsigned int i;
  unsigned int len2;
  char c;

  if(!s || pos >= mStr.size() - 1)
    return (unsigned int)~0;

  len2 = strlen(s);

  if(n >= len2)
    n = len2;

  c = mStr[pos];
  for(; c; c = mStr[++pos])
  {
    for(i = 0; i < n; ++i)
      if(c == s[i])
        break;
    if(i >= n)
      return pos;
  }

  return (unsigned int)~0;
}

unsigned int CString::find_first_not_of(const char *s, unsigned int pos) const
{
  return find_first_not_of(s, pos, (unsigned int)~0);
}

unsigned int CString::find_first_not_of(char c, unsigned int pos) const
{
  if(pos >= mStr.size() - 1)
    return (unsigned int)~0;

  for(; mStr[pos]; ++pos)
    if(mStr[pos] != c)
      return pos;

  return (unsigned int)~0;
}

unsigned int CString::find_last_not_of(const CString &str, unsigned int pos) const
{
  unsigned int i;
  unsigned int len2;
  char c;

  if(pos >= mStr.size() - 1)
    pos = mStr.size() - 2;

  len2 = str.mStr.size() - 1;

  for(++pos; pos--;)
  {
    c = mStr[pos];
    for(i = 0; i < len2; ++i)
      if(c == str.mStr[i])
        break;
    if(i >= len2)
      return pos;
  }

  return (unsigned int)~0;
}

unsigned int CString::find_last_not_of(const char *s, unsigned int pos, unsigned int n) const
{
  unsigned int i;
  unsigned int len1;
  unsigned int len2;
  char c;

  if(!s)
    return (unsigned int)~0;

  len1 = mStr.size() - 1;
  len2 = strlen(s);

  if(pos >= len1)
    pos = len1 - 1;

  if(n > len2)
    n = len2;

  for(++pos; pos--;)
  {
    c = mStr[pos];
    for(i = 0; i < n; ++i)
      if(c == s[i])
        break;
    if(i >= n)
      return pos;
  }

  return (unsigned int)~0;
}

unsigned int CString::find_last_not_of(const char *s, unsigned int pos) const
{
  return find_last_not_of(s, pos, (unsigned int)~0);
}

unsigned int CString::find_last_not_of(char c, unsigned int pos) const
{
  unsigned int len1 = mStr.size() - 1;

  if(pos >= len1)
    pos = len1 - 1;

  for(++pos; pos--;)
    if(mStr[pos] != c)
      return pos;

  return (unsigned int)~0;
}

CString CString::substr(unsigned int pos, unsigned int n) const
{
  return CString(*this, pos, n);
}

int CString::compare(const CString &str) const
{
  return compare(0, (unsigned int)~0, str, 0, (unsigned int)~0);
}

int CString::compare(const char *s) const
{
  return compare(0, (unsigned int)~0, s, (unsigned int)~0);
}

int CString::compare(unsigned int pos1, unsigned int n1, const CString &str) const
{
  return compare(pos1, n1, str, 0, (unsigned int)~0);
}

int CString::compare(unsigned int pos1, unsigned int n1, const char *s) const
{
  return compare(pos1, n1, s, (unsigned int)~0);
}

int CString::compare(unsigned int pos1, unsigned int n1, const CString &str, unsigned int pos2, unsigned int n2) const
{
  unsigned int ret = 0;
  unsigned int i;
  unsigned int len1 = mStr.size() - 1;
  unsigned int len2 = str.mStr.size() - 1;

  if(!len1 && !len2)
    return 0;

  if(pos1 >= len1 || pos2 >= len2)
    return -1;

  if(pos1 + n1 >= len1)
    n1 = len1 - pos1;

  if(pos2 + n2 >= len2)
    n2 = len2 - pos2;

  if(n2 > n1)
  {
    ret = 1;
    n1  = n2;
  }

  for(i = 0; i < n1; ++i)
    if(mStr[pos1 + i] != str.mStr[pos2 + i])
      return mStr[pos1 + i] >= str.mStr[pos2 + i] ? 1 : -1;

  return ret;
}

int CString::compare(unsigned int pos1, unsigned int n1, const char *s, unsigned int n2) const
{
  unsigned int ret = 0;
  unsigned int i;
  unsigned int len1 = mStr.size() - 1;
  unsigned int len2;

  if(!len1)
  { // GNU complained about the lack of brackets
    if(!s || !s[0])
      return 0;
    else
      return -1;
  }

  if(pos1 >= len1 || !s)
    return -1;

  if(pos1 + n1 >= len1)
    n1 = len1 - pos1;

  len2 = strlen(s);
  if(n2 >= len2)
    n2 = len2;

  if(n2 > n1)
  {
    ret = 1;
    n1  = n2;
  }

  for(i = 0; i < n1; ++i)
    if(mStr[pos1 + i] != s[i])
      return mStr[pos1 + i] >= s[i] ? 1 : -1;

  return ret;
}

int CString::SelfModification(const char *s)
{
  return s >= mStr.mData && s < mStr.mData + mStr.size();
}


void CString::ShiftRight(unsigned int start, unsigned int n)
{
  unsigned int read;
  unsigned int write;
  unsigned int end;

    // Calculate the new end of the string
  end = mStr.size() + n;
  mStr.reserve(end);
  mStr.RawSetCur(end);

  --end; // Set end to the last index

    // Shift over all the required elements
  for(read = end - n + 1, write = end; read-- > start; --write)
    mStr[write] = mStr[read];
}

bool operator==(const CString &lhs, const CString &rhs)
{
  return lhs.compare(rhs) == 0;
}

bool operator==(const char *lhs, const CString &rhs)
{
  return rhs.compare(lhs) == 0;
}

bool operator==(const CString &lhs, const char *rhs)
{
  return lhs.compare(rhs) == 0;
}

bool operator!=(const CString &lhs, const CString &rhs)
{
  return lhs.compare(rhs) != 0;
}

bool operator!=(const char *lhs, const CString &rhs)
{
  return rhs.compare(lhs) != 0;
}

bool operator!=(const CString &lhs, const char *rhs)
{
  return lhs.compare(rhs) != 0;
}

bool operator<(const CString &lhs, const CString &rhs)
{
  return lhs.compare(rhs) < 0;
}

bool operator<(const char *lhs, const CString &rhs)
{
  return rhs.compare(lhs) > 0;
}

bool operator<(const CString &lhs, const char *rhs)
{
  return lhs.compare(rhs) < 0;
}

bool operator>(const CString &lhs, const CString &rhs)
{
  return lhs.compare(rhs) > 0;
}

bool operator>(const char *lhs, const CString &rhs)
{
  return rhs.compare(lhs) < 0;
}

bool operator>(const CString &lhs, const char *rhs)
{
  return lhs.compare(rhs) > 0;
}

bool operator<=(const CString &lhs, const CString &rhs)
{
  return lhs.compare(rhs) <= 0;
}

bool operator<=(const char *lhs, const CString &rhs)
{
  return rhs.compare(lhs) > 0;
}

bool operator<=(const CString &lhs, const char *rhs)
{
  return lhs.compare(rhs) <= 0;
}

bool operator>=(const CString &lhs, const CString &rhs)
{
  return lhs.compare(rhs) >= 0;
}

bool operator>=(const char *lhs, const CString &rhs)
{
  return rhs.compare(lhs) < 0;
}

bool operator>=(const CString &lhs, const char *rhs)
{
  return lhs.compare(rhs) >= 0;
}

CString operator+(const CString &lhs, const CString &rhs)
{
  return CString(lhs) += rhs;
}

CString operator+(const char *lhs, const CString &rhs)
{
  return CString(lhs) += rhs;
}

CString operator+(char lhs, const CString &rhs)
{
  return CString(1, lhs) += rhs;
}

CString operator+(const CString &lhs, const char *rhs)
{
  return CString(lhs) += rhs;
}

CString operator+(const CString &lhs, char rhs)
{
  return CString(lhs) += rhs;
}







/******************************************************************************
 * Start of extensions                                                        *
 ******************************************************************************/






void CString::writef(const char *fmt, ...)
{
  CString temp;
  int written;
  va_list arg;

  temp.reserve(10 * 1024);

  va_start(arg, fmt);
  written = vsprintf(temp.mStr.mData, fmt, arg);
  va_end(arg);

  if(written >= 0)
  {
    if(written + 1 >= 10 * 1024)
    {
      printf("ERROR: Buffer overflow from vsprintf.\n");
      return;
    }

    temp.mStr.RawSetCur(written + 1);
    *this += temp;
  }
}

void CString::sprintf(const char *fmt, ...)
{
  CString temp;
  int written;
  va_list arg;

  temp.reserve(10 * 1024);

  va_start(arg, fmt);
  written = vsprintf(temp.mStr.mData, fmt, arg);
  va_end(arg);

  if(written >= 0)
  {
    if(written + 1 >= 10 * 1024)
    {
      printf("ERROR: Buffer overflow from vsprintf.\n");
      return;
    }

    temp.mStr.RawSetCur(written + 1);
    *this += temp;
  }
}

CString &CString::ToLower(void)
{
  unsigned int i;
  char c;

  for(i = 0, c = mStr[0]; c; c = mStr[++i])
    if(c >= 'A' && c <= 'Z')
      mStr[i] += (char)('a' - 'A');

  return *this;
}

CString CString::GetLower(void) const
{
  return CString(*this).ToLower();
}

CString &CString::ToUpper(void)
{
  unsigned int i;
  char c;

  for(i = 0, c = mStr[0]; c; c = mStr[++i])
    if(c >= 'a' && c <= 'z')
      mStr[i] += (char)('A' - 'a');

  return *this;
}

CString CString::GetUpper(void) const
{
  return CString(*this).ToUpper();
}

unsigned long CString::Hash(void)
{
  unsigned long hash = 0;
  unsigned int  len  = mStr.size() - 1;
  unsigned int  i;

  for(i = 0; i < len; ++i)
    hash = ((hash << 5) + ~hash) ^ (unsigned long)mStr.mData[i];

  return hash;
}

unsigned long CString::GetAsLong(void)
{
  unsigned long i, j;
  unsigned long res = 0;

  for(i = sizeof(unsigned long) - 1, j = 0; i != ~(unsigned long)0; --i, ++j)
    if(j < mStr.size() - 1)
      res |= mStr[j] << (8 * i);

  return res;
}
